﻿/*************************************************************************************
 * 工    具：  HK_TcpCommunicateSystem
 * 
 * 描    述：  本系统层是一个Unity的网络通信系统（不支持WebGL），包含了Server端和Client端两个部分，
 *            使用 TCP 协议实现客户端和服务器之间的消息传递。
 *            该系统通过 QFramework 框架进行管理，提供了服务器端和客户端的启动、关闭及消息发送等功能。
 * 
 * 版    本：  V1.0
 * 作    者：  京产肠饭
 * 
 * 创    建：  2024/07/04  V1.0
 *            
 * 链    接：  https://gitee.com/JingChanChangFan/hk_-unity-tools
*************************************************************************************/

using QFramework;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;

namespace HKTools
{
    public interface IHK_TcpServerSystem : ISystem
    {
        bool IsServerRunning { get; set; }

        /// <summary>
        /// 连接的Client端列表
        /// </summary>
        List<Socket> RemoteClients { get; set; }

        /// <summary>
        /// Server端 开启
        /// </summary>
        void StartServer(int port);

        /// <summary>
        /// Server端 关闭
        /// </summary>
        void CloseServer();

        /// <summary>
        /// Server端 给 所有Client端，发送消息
        /// </summary>
        /// <param name="msg"></param>
        void SendMsg_ServerToAllClients(string msg);

        /// <summary>
        /// 通过 Socket，Server端 给 Client端，发送消息
        /// </summary>
        /// <param name="ipAndPort"></param>
        /// <param name="msg"></param>
        void SendMsg_ServerToClient(Socket remoteSocket, string msg);

        /// <summary>
        /// 设置是否开启 系统层Debug
        /// </summary>
        /// <param name="isOn"></param>
        void SetDebugState(bool isOn);
    }

    public class HK_TcpServerSystem : AbstractSystem, IHK_TcpServerSystem
    {
        public bool IsServerRunning { get; set; }
        public List<Socket> RemoteClients { get; set; }

        Socket serverSocket;

        SynchronizationContext mainThreadContext;

        bool isDebugOn = false;

        protected override void OnInit()
        {
            IsServerRunning = false;
            mainThreadContext = SynchronizationContext.Current;
            RemoteClients = new List<Socket>(); // 初始化客户端列表

            // Server端 系统层不进行Debug打印
            SetDebugState(false);
        }

        public void StartServer(int port)
        {
            if (IsServerRunning)
            {
                Debug.LogWarning("Server端已经启动，不能重复启动！");
                return;
            }

            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), port);
            serverSocket.Bind(ipEndPoint);
            serverSocket.Listen(1024);
            HKDebug.Log("Server端 开启，等待客户端连接...", LogColor.Blue);
            IsServerRunning = true;

            ThreadPool.QueueUserWorkItem(StartServer_ThreadMethod);
        }

        void StartServer_ThreadMethod(object obj)
        {
            while (IsServerRunning)
            {
                try
                {
                    if (serverSocket.Poll(1000, SelectMode.SelectRead))
                    {
                        Socket remoteClient = serverSocket.Accept();
                        IPEndPoint remoteEndPoint = (IPEndPoint)remoteClient.RemoteEndPoint;

                        RemoteClients.Add(remoteClient); // 添加新客户端到列表

                        remoteClient.Send(Encoding.UTF8.GetBytes("欢迎连入服务器..."));

                        mainThreadContext.Post(_ =>
                        {
                            if (isDebugOn)
                                HKDebug.Log($"Client({remoteEndPoint.Address}:{remoteEndPoint.Port}) 连接成功!", LogColor.Blue);

                            this.SendEvent(new Event_TCP_ClientConnect() { _address = remoteEndPoint.Address.ToString(), _port = remoteEndPoint.Port });
                        }, null);

                        ThreadPool.QueueUserWorkItem(HandleClient_ThreadMethod);
                    }
                }
                catch (SocketException e)
                {
                    Debug.LogError(e.Message);
                }
            }
        }

        void HandleClient_ThreadMethod(object obj)
        {
            while (IsServerRunning)
            {
                if (RemoteClients.Count <= 0)
                    continue;

                foreach (var remoteClient in RemoteClients)
                {
                    try
                    {
                        if (remoteClient.Available <= 0)
                        {
                            //Thread.Sleep(10); // 避免忙等待
                            continue;
                        }

                        // 接收客户端发送来的消息
                        byte[] msgBytes = new byte[1024];
                        int msgLength = remoteClient.Receive(msgBytes);

                        string clientMessage = Encoding.UTF8.GetString(msgBytes, 0, msgLength);

                        mainThreadContext.Post(_ =>
                        {
                            if (isDebugOn)
                                Debug.Log($"Client({(remoteClient.RemoteEndPoint as IPEndPoint).Address}:{(remoteClient.RemoteEndPoint as IPEndPoint).Port}) 消息：" + clientMessage);

                            this.SendEvent(new Event_TCP_FromClientMsg() { _address = (remoteClient.RemoteEndPoint as IPEndPoint).Address.ToString(), _port = (remoteClient.RemoteEndPoint as IPEndPoint).Port, _msg = clientMessage });

                            if (clientMessage.Trim().Equals("CLIENTCLOSE"))
                            {
                                if (isDebugOn)
                                    HKDebug.Log($"Client({(remoteClient.RemoteEndPoint as IPEndPoint).Address}:{(remoteClient.RemoteEndPoint as IPEndPoint).Port}) 断开连接!", LogColor.Blue);

                                RemoteClients.Remove(remoteClient); // 从列表中移除Client

                                this.SendEvent(new Event_TCP_ClientDisConnect() { _address = (remoteClient.RemoteEndPoint as IPEndPoint).Address.ToString(), _port = (remoteClient.RemoteEndPoint as IPEndPoint).Port });

                                remoteClient.Shutdown(SocketShutdown.Both);
                                remoteClient.Close(); // 关闭客户端连接
                            }
                        }, null);
                    }
                    catch
                    {
                        Debug.LogWarning("Client端 异常！");

                        // 客户端断开连接
                        mainThreadContext.Post(_ =>
                        {
                            if (isDebugOn)
                                HKDebug.Log($"Client({(remoteClient.RemoteEndPoint as IPEndPoint).Address}:{(remoteClient.RemoteEndPoint as IPEndPoint).Port}) 断开连接!", LogColor.Blue);

                            RemoteClients.Remove(remoteClient); // 从列表中移除Client

                            this.SendEvent(new Event_TCP_ClientDisConnect() { _address = (remoteClient.RemoteEndPoint as IPEndPoint).Address.ToString(), _port = (remoteClient.RemoteEndPoint as IPEndPoint).Port });

                            remoteClient.Shutdown(SocketShutdown.Both);
                            remoteClient.Close(); // 关闭客户端连接
                        }, null);
                    }
                }
            }
        }

        public void SendMsg_ServerToAllClients(string msg)
        {
            if (!IsServerRunning)
                return;

            foreach (var remoteClient in RemoteClients)
            {
                // 添加检查以确保Socket已连接
                if (remoteClient != null && remoteClient.Connected)
                {
                    remoteClient.Send(Encoding.UTF8.GetBytes(msg));
                }
            }
        }

        public void SendMsg_ServerToClient(Socket remoteSocket, string msg)
        {
            if (!IsServerRunning)
                return;

            if (remoteSocket != null && remoteSocket.Connected)
            {
                remoteSocket.Send(Encoding.UTF8.GetBytes(msg));
            }
        }

        public void CloseServer()
        {
            if (!IsServerRunning)
                return;

            SendMsg_ServerToAllClients("SERVERCLOSE");

            lock (RemoteClients) // 加锁确保线程安全
            {
                foreach (var client in RemoteClients)
                {
                    if (client != null)
                    {
                        client.Shutdown(SocketShutdown.Both);
                        client.Close();
                    }
                }

                RemoteClients.Clear(); // 清空客户端列表
            }

            if (serverSocket != null)
            {
                serverSocket.Close();
                serverSocket = null;
            }

            IsServerRunning = false;
            HKDebug.Log("Server端 关闭", LogColor.Red);
        }

        public void SetDebugState(bool isOn)
        {
            isDebugOn = isOn;
        }
    }
}